home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / util / faxcron.sh < prev    next >
Linux/UNIX/POSIX Shell Script  |  1994-08-01  |  10KB  |  372 lines

  1. #! /bin/sh
  2. #    $Header: /usr/people/sam/fax/util/RCS/faxcron.sh,v 1.8 1994/04/18 21:35:05 sam Rel $
  3. #
  4. # FlexFAX Facsimile Software
  5. #
  6. # Copyright (c) 1993, 1994 Sam Leffler
  7. # Copyright (c) 1993, 1994 Silicon Graphics, Inc.
  8. # Permission to use, copy, modify, distribute, and sell this software and 
  9. # its documentation for any purpose is hereby granted without fee, provided
  10. # that (i) the above copyright notices and this permission notice appear in
  11. # all copies of the software and related documentation, and (ii) the names of
  12. # Sam Leffler and Silicon Graphics may not be used in any advertising or
  13. # publicity relating to the software without the specific, prior written
  14. # permission of Sam Leffler and Silicon Graphics.
  15. # THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  16. # EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  17. # WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  18. # IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19. # ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20. # OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21. # WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22. # LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23. # OF THIS SOFTWARE.
  24. #
  25.  
  26. #
  27. # Script to run periodically from cron:
  28. #
  29. # 1. Purge info directory of old remote machine capabilities.
  30. # 2. Truncate log files to delete old information.
  31. # 3. Purge old files in the received facsimile queue.
  32. # 4. Notify about sites that are currently having jobs rejected.
  33. #
  34. SPOOL=/usr/spool/fax
  35. JUNK=/tmp/faxcron$$
  36. XFERLOG=$SPOOL/etc/xferlog
  37. LAST=$SPOOL/etc/lastrun
  38.  
  39. AGEINFO=30            # purge remote info after 30 days inactivity
  40. AGELOG=30            # keep log info for last 30 days
  41. FAXUSER=fax            # owner of log files
  42. LOGMODE=0644            # mode for log files
  43.  
  44. PATH=/bin:/usr/bin:/etc
  45. test -d /usr/ucb  && PATH=$PATH:/usr/ucb        # Sun and others
  46. test -d /usr/bsd  && PATH=$PATH:/usr/bsd        # Silicon Graphics
  47. test -d /usr/5bin && PATH=/usr/5bin:$PATH:/usr/etc    # Sun and others
  48. test -d /usr/sbin && PATH=/usr/sbin:$PATH        # 4.4BSD-derived
  49.  
  50. AWK=nawk
  51. # look for an an awk: nawk, gawk, awk
  52. ($AWK '{}' </dev/null >/dev/null) 2>/dev/null ||
  53.     { AWK=gawk; ($AWK '{}' </dev/null >/dev/null) 2>/dev/null || AWK=awk; }
  54.  
  55. RM="rm -f"
  56. TEE=tee
  57. CP=cp
  58. MV=mv
  59. CHOWN=chown
  60. CHMOD=chmod
  61. UPDATE="date +'%D %R' >$LAST"
  62.  
  63. while [ x"$1" != x"" ] ; do
  64.     case $1 in
  65.     -n)        RM=true; TEE=true; CP=true; MV=true;
  66.         CHOWN=true; CHMOD=true
  67.         UPDATE=true
  68.         ;;
  69.     -*)        echo "Usage: $0 [-n]"; exit 1;;
  70.     esac
  71.     shift
  72. done
  73.  
  74. trap "rm -f \$JUNK; exit 1" 0 1 2 15
  75.  
  76. cd $SPOOL
  77.  
  78. echo "Report failed calls and associated session logs:"
  79. LASTRUN=`cat $LAST 2>/dev/null`
  80. $AWK '
  81. #
  82. # Sort array a[l..r]
  83. #
  84. function qsort(a, l, r) {
  85.     i = l;
  86.     k = r+1;
  87.     item = a[l];
  88.     for (;;) {
  89.     while (i < r) {
  90.             i++;
  91.         if (a[i] >= item)
  92.         break;
  93.         }
  94.     while (k > l) {
  95.             k--;
  96.         if (a[k] <= item)
  97.         break;
  98.         }
  99.         if (i >= k)
  100.         break;
  101.     t = a[i]; a[i] = a[k]; a[k] = t;
  102.     }
  103.     t = a[l]; a[l] = a[k]; a[k] = t;
  104.     if (k != 0 && l < k-1)
  105.     qsort(a, l, k-1);
  106.     if (k+1 < r)
  107.     qsort(a, k+1, r);
  108. }
  109.  
  110. func cleanup(s)
  111. {
  112.     gsub("\"", "", s);
  113.     gsub("^ +", "", s);
  114.     gsub(" +$", "", s);
  115.     return s;
  116. }
  117.  
  118. func isBefore(d)
  119. {
  120.     split(d, a, " ");
  121.     split(a[1], b, "/");
  122.     return (b[3] < LASTd[3] \
  123.      || b[2] < LASTd[2] \
  124.      || b[1] < LASTd[1] \
  125.      || a[2] <= LASTdt[2]);
  126. }
  127.  
  128. func setupToLower()
  129. {
  130.     upperRE = "[ABCDEFGHIJKLMNOPQRSTUVWXYZ]";
  131.     upper["A"] = "a"; upper["B"] = "b"; upper["C"] = "c";
  132.     upper["D"] = "d"; upper["E"] = "e"; upper["F"] = "f";
  133.     upper["G"] = "g"; upper["H"] = "h"; upper["I"] = "i";
  134.     upper["J"] = "j"; upper["K"] = "k"; upper["L"] = "l";
  135.     upper["M"] = "m"; upper["N"] = "n"; upper["O"] = "o";
  136.     upper["P"] = "p"; upper["Q"] = "q"; upper["R"] = "r";
  137.     upper["S"] = "s"; upper["T"] = "t"; upper["U"] = "u";
  138.     upper["V"] = "v"; upper["W"] = "w"; upper["X"] = "x";
  139.     upper["Y"] = "y"; upper["Z"] = "z";
  140. }
  141.  
  142. func toLower(s)
  143. {
  144.     if (match(s, upperRE) != 0) {
  145.     do {
  146.         c = substr(s, RSTART, 1);
  147.         gsub(c, upper[c], s);
  148.     } while (match(s, upperRE));
  149.     }
  150.     return s;
  151. }
  152.  
  153. #
  154. # Accumulate a statistics record.
  155. #
  156. func acct(dest, status, datetime)
  157. {
  158.     if (isBefore(datetime))
  159.     return;
  160.     status = cleanup(status);
  161.     if (length(status) > 11) {
  162.     msg = toLower(substr(status, 1, 11));
  163.     if (callFailed[msg])
  164.         return;
  165.     if (skipError[msg])
  166.         return;
  167.     }
  168.     if (status != "") {
  169.     dest = cleanup(dest);
  170.     datetime = cleanup(datetime);
  171.     for (i = 0; i < nerrmsg; i++)
  172.         if (errmsg[i] == status)
  173.         break;
  174.     if (i == nerrmsg)
  175.         errmsg[nerrmsg++] = status;
  176.     if (errinfo[dest] == "")
  177.         errinfo[dest] = datetime "@" i;
  178.     else
  179.         errinfo[dest] = errinfo[dest] "|" datetime "@" i;
  180.     }
  181. }
  182.  
  183. func printTranscript(canon, datetime)
  184. {
  185.     gsub("[^0-9]", "", canon);
  186.     split(datetime, parts, " ");
  187.     split(parts[1], p, "/");
  188.     cmd = sprintf(TRANSCRIPT, canon, months[p[1]], p[2], parts[2]);
  189.     system(cmd);
  190. }
  191.  
  192. BEGIN        { FS="\t";
  193.           callFailed["busy signal"] = 1;
  194.           callFailed["unknown pro"] = 1;
  195.           callFailed["no carrier "] = 1;
  196.           callFailed["no local di"] = 1;
  197.           callFailed["no answer f"] = 1;
  198.            skipError["job aborted"] = 1;
  199.            skipError["invalid dia"] = 1;
  200.            skipError["can not loc"] = 1;
  201.           months["01"] = "Jan"; months["02"] = "Feb";
  202.           months["03"] = "Mar"; months["04"] = "Apr";
  203.           months["05"] = "May"; months["06"] = "Jun";
  204.           months["07"] = "Jul"; months["08"] = "Aug";
  205.           months["09"] = "Sep"; months["10"] = "Oct";
  206.           months["11"] = "Nov"; months["12"] = "Dec";
  207.  
  208.           split(LASTRUN, LASTdt, " ");
  209.           split(LASTdt[1], LASTd, "/");
  210.           setupToLower();
  211.         }
  212. $2 == "SEND" && NF == 9  { acct($4, $9, $1); }
  213. $2 == "SEND" && NF == 11 { acct($5, $11, $1); }
  214. END        { nsorted = 0;
  215.           for (key in errinfo)
  216.               sorted[nsorted++] = key;
  217.           qsort(sorted, 0, nsorted-1);
  218.           for (k = 0; k < nsorted; k++) {
  219.               key = sorted[k];
  220.               n = split(errinfo[key], a, "|");
  221.               for (i = 1; i <= n; i++) {
  222.               m = split(a[i], b, "@");
  223.               if (m != 2)
  224.                   continue;
  225.               printf "\n"
  226.               printf "To: %-16.16s  Date: %s\n", key, b[1]
  227.               printf "Error: %s\n\n", errmsg[b[2]]
  228.  
  229.               printTranscript(key, b[1]);
  230.               }
  231.           }
  232.         }
  233. ' LASTRUN="$LASTRUN" TRANSCRIPT="\
  234.     LOGFILE=$SPOOL/log/%s;\
  235.     TMP=/tmp/faxlog\$\$;\
  236.     if [ -f \$LOGFILE ]; then\
  237.     sed -n -e '/%s %s %s.*SESSION BEGIN/,/SESSION END/p' \$LOGFILE |\
  238.     sed -e '/start.*timer/d'\
  239.         -e '/stop.*timer/d'\
  240.         -e '/-- data/d'\
  241.         -e 's/^/    /' >\$TMP;\
  242.     fi;\
  243.     if [ -s \$TMP ]; then\
  244.     cat \$TMP;\
  245.     else\
  246.     echo '    No transcript available.';\
  247.     fi;\
  248.     rm -f \$TMP\
  249.     " $XFERLOG
  250. $RM $LAST; eval $UPDATE
  251. echo ""
  252.  
  253. #
  254. # Collect phone numbers that haven't been called
  255. # in the last $AGE days.  We use this to clean up
  256. # the info and log files.
  257. #
  258. find info -ctime +$AGEINFO -print >$JUNK
  259.  
  260. echo "Purge cache of fax machine capabilities:"
  261. for i in `cat $JUNK`; do
  262.     echo "    $i"
  263.     $RM $i
  264. done
  265. echo ""
  266.  
  267. echo "Truncate old session logs:"
  268. TODAY="`date +'%h %d %T'`"
  269. for i in log/*; do
  270.     START=`$AWK -F: '
  271. #
  272. # Setup data conversion data structures.
  273. #
  274. func setupDateTimeStuff()
  275. {
  276.     Months["Jan"] =  0; Months["Feb"] =  1; Months["Mar"] =  2;
  277.     Months["Apr"] =  3; Months["May"] =  4; Months["Jun"] =  5;
  278.     Months["Jul"] =  6; Months["Aug"] =  7; Months["Sep"] =  8;
  279.     Months["Oct"] =  9; Months["Nov"] = 10; Months["Dec"] = 11;
  280.  
  281.     daysInMonth[ 0] = 31; daysInMonth[ 1] = 28; daysInMonth[ 2] = 31;
  282.     daysInMonth[ 3] = 30; daysInMonth[ 4] = 31; daysInMonth[ 5] = 30;
  283.     daysInMonth[ 6] = 31; daysInMonth[ 7] = 31; daysInMonth[ 8] = 30;
  284.     daysInMonth[ 9] = 31; daysInMonth[10] = 30; daysInMonth[11] = 31;
  285.  
  286.     FULLDAY = 24 * 60 * 60;
  287. }
  288.  
  289. #
  290. # Convert MMM DD hh:mm:ss.ms to seconds.
  291. # NB: this does not deal with leap years.
  292. #
  293. func cvtTime(s)
  294. {
  295.     mon = Months[substr(s, 0, 3)];
  296.     yday = substr(s, 5, 2) - 1;
  297.     for (i = 0; i < mon; i++)
  298.     yday += daysInMonth[i];
  299.     s = substr(s, 7);
  300.     t = i = 0;
  301.     for (n = split(s, a, ":"); i++ < n; )
  302.     t = t*60 + a[i];
  303.     return yday*FULLDAY + t;
  304. }
  305.  
  306. BEGIN            { setupDateTimeStuff();
  307.               KEEP = cvtTime(TODAY) - AGE*FULLDAY;
  308.               lastRecord = "$"
  309.             }
  310.             { if (cvtTime($1 ":" $2 ":" $3) >= KEEP) {
  311.                   lastRecord = NR; exit
  312.               }
  313.             }
  314. END            { print lastRecord }
  315. ' TODAY="$TODAY" AGE=$AGELOG $i` 2>/dev/null
  316.     if [ "$START" != 1 ]; then
  317.     sed 1,${START}d $i >$JUNK
  318.     if [ -s $JUNK ]; then
  319.         $MV $JUNK $i; $CHOWN ${FAXUSER} $i; $CHMOD ${LOGMODE} $i
  320.         ls -ls $i
  321.     else
  322.         echo "     Remove empty $i"
  323.         $RM $i
  324.     fi
  325.     fi
  326. done
  327. echo ""
  328.  
  329. #
  330. # Purge old stuff from the receive queue.
  331. #
  332. find recvq -mtime +7 -print >$JUNK
  333.  
  334. echo "Purge old stuff in receive queue:"
  335. if [ -s $JUNK ]; then
  336.     (for i in `cat $JUNK`; do
  337.     bin/faxinfo $i
  338.     $RM $i >/dev/null 2>&1
  339.     done) | $AWK -F: '
  340. /recvq.*/    { file=$1; }
  341. /Sender/    { sender = $2; }
  342. /Pages/        { pages = $2; }
  343. /Quality/    { quality = $2; }
  344. /Received/    { date = $2;
  345.           for (i = 3; i <= NF; i++)
  346.               date = date ":" $i;
  347.           printf "    %-16.16s %21.21s %2d %8s%s\n", \
  348.             file, sender, pages, quality, date;
  349.         }
  350. '
  351. fi
  352. echo ""
  353.  
  354. #
  355. # Note destinations whose jobs are currently being rejected.
  356. #
  357. grep "^rejectNotice:" info/* cinfo/* 2>/dev/null | $AWK -F: '
  358.         { reason = $3;
  359.           for (i = 4; i <= NF; i++)
  360.             reason = reason ":" $i;
  361.           sub("^[ ]*", "", reason);
  362.           if (reason != "") {
  363.               sub(".*/", "", $1);
  364.               printf "Rejecting jobs to +%s because \"%s\".\n", \
  365.                 $1, reason;
  366.           }
  367.         }
  368. '
  369.